/**
 *
 */
package com.shuaqiu.simback.dao.impl;

import com.shuaqiu.simback.dao.DBOperate;
import com.shuaqiu.simback.model.Model;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.inject.Inject;
import javax.inject.Named;
import java.util.List;
import java.util.Map;

/**
 * @author qiushaohua
 */
@Transactional
@Named
public class DBOperateImpl implements DBOperate {

    private static final Log log = LogFactory.getLog(DBOperateImpl.class);

    private JdbcTemplate jdbcTemplate;
    private SqlBuilder sqlBuilder;

    /**
     * @param jdbcTemplate the jdbcTemplate to set
     */
    @Inject
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * @param sqlBuilder
     */
    @Inject
    public void setSqlBuilder(SqlBuilder sqlBuilder) {
        this.sqlBuilder = sqlBuilder;
    }

    @Transactional(readOnly = true)
    public <T extends Model> T getBo(Class<T> clazz, Integer id) {
        String sql = buildSelectById(clazz);
        ModelRowMapper<T> rowMapper = ModelRowMapper.Factory.getInstance(clazz);
        T obj = jdbcTemplate.queryForObject(sql, rowMapper, id);
        return obj;
    }

    @Transactional(readOnly = true)
    public <T extends Model> Map<String, Object> getMap(Class<T> clazz, Integer id) {
        String sql = buildSelectById(clazz);
        Map<String, Object> map = jdbcTemplate.queryForMap(sql, id);
        return map;
    }

    private <T extends Model> String buildSelectById(Class<T> clazz) {
        String sql = sqlBuilder.buildSelect(clazz) + " where id = ?";
        log.debug(sql);

        return sql;
    }

    @Transactional(readOnly = true)
    public <T extends Model> List<T> getBoList(Class<T> clazz, String sqlCondition, Object... args) {
        String sql = buildSelect(clazz, sqlCondition);

        ModelRowMapper<T> rowMapper = ModelRowMapper.Factory.getInstance(clazz);
        List<T> list = jdbcTemplate.query(sql, rowMapper, args);
        return list;
    }

    @Transactional(readOnly = true)
    public <T extends Model> List<Map<String, Object>> getMapList(Class<T> clazz, String sqlCondition, Object... args) {
        String sql = buildSelect(clazz, sqlCondition);
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, args);

        return list;
    }

    private <T extends Model> String buildSelect(Class<T> clazz, String sqlCondition) {
        String sql = sqlBuilder.buildSelect(clazz);
        if (StringUtils.hasText(sqlCondition)) {
            sql += " where " + sqlCondition;
        }
        log.debug(sql);

        return sql;
    }

    public <T extends Model> int deleteBo(Class<T> clazz, String sqlCondition, Object... args) {
        String sql = sqlBuilder.buildDelete(clazz);
        if (StringUtils.hasText(sqlCondition)) {
            sql += " where " + sqlCondition;
        }
        log.debug(sql);

        return jdbcTemplate.update(sql, args);
    }

    public <T extends Model> String saveOrUpdateBo(T bo) {
        if (bo.getId() == null) {
            insert(bo);
            return "";
        }
        boolean isExist = isExist(bo);
        if (isExist) {
            update(bo);
        } else {
            insert(bo);
        }
        return null;
    }

    private <T extends Model> boolean isExist(T bo) {
        String sql = sqlBuilder.buildExist(bo);
        log.debug(sql);

        Integer count = jdbcTemplate.queryForObject(sql, Integer.class, bo.getId());
        return count  == 1;
    }


    private <T extends Model> int insert(T bo) {
        String sql = sqlBuilder.buildInsert(bo);
        log.debug(sql);

        Object[] args = sqlBuilder.buildInsertParams(bo);
        return jdbcTemplate.update(sql, args);
    }

    private <T extends Model> int update(T bo) {
        String sql = sqlBuilder.buildUpdate(bo);
        log.debug(sql);

        Object[] args = sqlBuilder.buildUpdateParams(bo);
        return jdbcTemplate.update(sql, args);
    }

    public void sql(String sql) {
        log.debug(sql);

        jdbcTemplate.execute(sql);
    }

}
